/*
-----------------------------------------------------------------------------
This source file is part of Labor3D
(Labor 3D Graphics Engine)

Copyright (c) 2009-2020 Rock Mao
* creator : Rock Mao
* created : 2009-6-27   22:29
* filename: LaborGPUProgram.cpp
-----------------------------------------------------------------------------
*/

#include "Renderer/LaborInputLayout.h"
#include "Common/LaborHashString.h"
#include "Renderer/LaborRenderSystemHeader.h"
NAMESPACE_LABOR3D_BEGIN

CLInputElementTypeInfo::CLInputElementTypeInfo(const eLShaderVariableType& vet)
{
	xShaderVarInfo info;
	SHADER_VAR_PARSER()->shaderVarInfo(vet , info);
	m_dataType         = info.m_dataType;
	m_nComponent       = info.m_nCol * info.m_nRow;
	m_bytePerComponent = info.m_bytePerComponent;
	m_stride           = m_nComponent * m_bytePerComponent;
	type = vet;
}

CLShaderVariableParser::CLShaderVariableParser()
{
	//D3D
	_insert("float" ,eL_SVT_FLOAT );
	_insert("float2",eL_SVT_FLOAT2 );
	_insert("float3",eL_SVT_FLOAT3 );
	_insert("float4",eL_SVT_FLOAT4 );

	_insert("half",eL_SVT_HALF     );
	_insert("half2",eL_SVT_HALF2   );
	_insert("half3",eL_SVT_HALF3   );
	_insert("half4",eL_SVT_HALF4   );

	_insert("int",eL_SVT_INT       );
	_insert("int2",eL_SVT_INT2     );
	_insert("int3",eL_SVT_INT3     );
	_insert("int4",eL_SVT_INT4     );

	_insert("short",eL_SVT_SHORT   );
	_insert("short2",eL_SVT_SHORT2 );
	_insert("short3",eL_SVT_SHORT3 );
	_insert("short4",eL_SVT_SHORT4 );

	//Matrix															
	_insert("float4x4",eL_SVT_Matrix          );
	_insert("float3x3",eL_SVT_Matrix3x3       );
	_insert("float4x3",eL_SVT_Matrix4x3       );
	_insert("float3x4",eL_SVT_Matrix3x4       );

	//Object
	_insert("Sampler"    ,eL_SVT_Sampler    );
	_insert("Texture"    ,eL_SVT_Texture    );
	//_insert("Texture1D"  ,eL_SVT_Texture1D  );
	_insert("Texture2D"  ,eL_SVT_Texture2D  );
	_insert("Texture3D"  ,eL_SVT_Texture3D  );
	_insert("TextureCube",eL_SVT_TextureCube);
}
CLShaderVariableParser::~CLShaderVariableParser()
{

}
CLShaderVariableParser* CLShaderVariableParser::singleton()
{
	static CLShaderVariableParser gs_parser;
	return &gs_parser;
}
void CLShaderVariableParser::_insert(const char* typeName , eLShaderVariableType _et)
{
	int id = fLStringHash(typeName);
	m_mapTypes.insert(mapShaderVarTypes::value_type(id , _et) );
}

bool CLShaderVariableParser::shaderVarInfo(const char* varType , xShaderVarInfo& info)
{
	int id = fLStringHash(varType);
	mapShaderVarTypes::iterator pos = m_mapTypes.find(id);
	if(pos == m_mapTypes.end() )
		return false;
	return shaderVarInfo(pos->second , info);
}

bool CLShaderVariableParser::shaderVarInfo(eLShaderVariableType varType , xShaderVarInfo& info)
{
	int it = (int)varType;
	info.m_Type = varType;
	info.m_dataType = (eLShaderVariableDataType)(it >> 16);
	short ut = it & 0x0000ffff;
	info.m_nCol = ut>>8;
	info.m_nRow = ut & 0x00ff;
	info.m_bytePerComponent = info.m_dataType & 0x00ff;
	return true;
}

eLVertexElementSemantic CLShaderVariableParser::shaderVarSemantic(const wchar_t* _semanticName)
{
	std::wstring semanticName = _semanticName;

	if( semanticName == SHADER_SEMANTIC_POSITION ) 
		return el_VES_POSITION  ; 
	if( semanticName == SHADER_SEMANTIC_NORMAL ) 
		return el_VES_NORMAL   ;  
	if( semanticName == SHADER_SEMANTIC_TANGENT ) 
		return el_VES_TANGENT;    
	if( semanticName == SHADER_SEMANTIC_BINORMAL ) 
		return el_VES_BINORMAL;   
	if( semanticName == SHADER_SEMANTIC_TEXCOORD ) 
		return el_VES_TEXTURE_COORDINATES ;  
	if( semanticName == SHADER_SEMANTIC_COLOR ) 
		return el_VES_DIFFUSE ;   
	if( semanticName == SHADER_SEMANTIC_ANY  ) 
		return eL_VES_ANY  ;      
	return eL_VES_ANY  ; 
}

const wchar_t* CLShaderVariableParser::shaderVarSemantic(eLVertexElementSemantic semantic)
{
	if(semantic == el_VES_POSITION )
		return    SHADER_SEMANTIC_POSITION  ; 
	if(semantic == el_VES_NORMAL   )
		return    SHADER_SEMANTIC_NORMAL    ; 
	if(semantic == el_VES_TANGENT  ) 
		return    SHADER_SEMANTIC_TANGENT   ; 
	if(semantic == el_VES_BINORMAL ) 
		return    SHADER_SEMANTIC_BINORMAL  ; 
	if(semantic == el_VES_TEXTURE_COORDINATES ) 
		return    SHADER_SEMANTIC_TEXCOORD  ; 
	if(semantic == el_VES_DIFFUSE  ) 
		return    SHADER_SEMANTIC_COLOR   ; 
	if(semantic == eL_VES_ANY      ) 
		return    SHADER_SEMANTIC_ANY       ; 
	return    SHADER_SEMANTIC_ANY       ; 

}

//---------------------------------------------------------------------
CLInputLayoutDesc::CLInputLayoutDesc()
{
	m_vInputElemets.reserve(16);
}

//---------------------------------------------------------------------
CLInputLayoutDesc::~CLInputLayoutDesc()
{

}

//---------------------------------------------------------------------
bool CLInputLayoutDesc::addElement(sLInputElement& element)
{
	if(element.m_offset <= 0 )
	{
		element.m_offset = nStrideOfBuffer(element.m_InputSlot);
	}
	m_vInputElemets.push_back(element);
	return true;
}

//---------------------------------------------------------------------
bool CLInputLayoutDesc::addElement(wchar_t* semantic ,eLShaderVariableType veType , 
				size_t sematicIdx, 
				size_t bufIdx, 
				int    bufOffset,
				eLInputClassIfication inputUsage,
				size_t      instanceDataStepRate
				)
{
	sLInputElement el;
	if(bufOffset < 0)
	{ 
		bufOffset = (int)nStrideOfBuffer(bufIdx);
	}

	el.m_InputSlot  = bufIdx;
	el.m_offset = bufOffset;
	el.m_InputUsage = inputUsage;
	el.m_InstanceDataStepRate = instanceDataStepRate;
	wcsncpy(el.m_Semantic , semantic , 16);
	el.m_SemanticIdx = sematicIdx;
	el.m_Type = veType;
	m_vInputElemets.push_back(el);
	return true;
}

const size_t CLInputLayoutDesc::nStrideOfBuffer(size_t bufIdx)  const
{
	size_t bufSize = 0;
	for(size_t i = 0 ; i < m_vInputElemets.size() ; i ++)
	{
		const sLInputElement& _el = m_vInputElemets[i];
		if(_el.m_InputSlot == bufIdx )
		{
			CLInputElementTypeInfo ieti(_el.m_Type);
			bufSize += ieti.m_stride;
		}
	}
	return bufSize;
}


NAMESPACE_LABOR3D_END